package cc.shacocloud.kotlin.tools.amqp

import com.rabbitmq.client.AMQP.BasicProperties
import java.util.*

/**
 *
 * @author 思追(shaco)
 */
data class Message(

    /**
     * 消息体
     */
    val body: ByteArray,

    /**
     * 内容类型
     */
    val contentType: String = "application/octet-stream",

    /**
     * 内容编码
     */
    val contentEncoding: String = "UTF-8",

    /**
     * [BasicProperties.headers]
     */
    val headers: Map<String, Any> = emptyMap(),

    /**
     * [BasicProperties.deliveryMode]
     */
    val deliveryMode: MessageDeliveryMode = MessageDeliveryMode.PERSISTENT,

    /**
     * [BasicProperties.priority]
     */
    val priority: Int = 0,

    /**
     * [BasicProperties.correlationId]
     */
    val correlationId: String? = null,

    /**
     * [BasicProperties.replyTo]
     */
    val replyTo: String? = null,

    /**
     * [BasicProperties.expiration]
     *
     * 设置消息过期时间。这是符合 AMQP 0.9.1 规范的 String 属性。对于 RabbitMQ，这是以毫秒为单位的消息时间的 String 表示形式。
     */
    val expiration: String? = null,

    /**
     * [BasicProperties.messageId]
     */
    val messageId: String? = null,

    /**
     * [BasicProperties.messageId]
     */
    val timestamp: Date? = null,

    /**
     * [BasicProperties.type]
     */
    val type: String? = null,

    /**
     * [BasicProperties.userId]
     */
    val userId: String? = null,

    /**
     * [BasicProperties.appId]
     */
    val appId: String? = null,

    /**
     * [BasicProperties.clusterId]
     */
    val clusterId: String? = null

) {

    /**
     * 转为 amqp 的 [BasicProperties]
     */
    fun toBasicProperties(): BasicProperties {
        return BasicProperties(
            contentType,
            contentEncoding,
            headers,
            deliveryMode.toInt(),
            priority,
            correlationId,
            replyTo,
            expiration,
            messageId,
            timestamp,
            type,
            userId,
            appId,
            clusterId
        )
    }

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other !is Message) return false

        if (!body.contentEquals(other.body)) return false
        if (contentType != other.contentType) return false
        if (contentEncoding != other.contentEncoding) return false
        if (headers != other.headers) return false
        if (deliveryMode != other.deliveryMode) return false
        if (priority != other.priority) return false
        if (correlationId != other.correlationId) return false
        if (replyTo != other.replyTo) return false
        if (expiration != other.expiration) return false
        if (messageId != other.messageId) return false
        if (timestamp != other.timestamp) return false
        if (type != other.type) return false
        if (userId != other.userId) return false
        if (appId != other.appId) return false
        if (clusterId != other.clusterId) return false

        return true
    }

    override fun hashCode(): Int {
        var result = body.contentHashCode()
        result = 31 * result + contentType.hashCode()
        result = 31 * result + contentEncoding.hashCode()
        result = 31 * result + headers.hashCode()
        result = 31 * result + deliveryMode.hashCode()
        result = 31 * result + priority
        result = 31 * result + (correlationId?.hashCode() ?: 0)
        result = 31 * result + (replyTo?.hashCode() ?: 0)
        result = 31 * result + (expiration?.hashCode() ?: 0)
        result = 31 * result + (messageId?.hashCode() ?: 0)
        result = 31 * result + (timestamp?.hashCode() ?: 0)
        result = 31 * result + (type?.hashCode() ?: 0)
        result = 31 * result + (userId?.hashCode() ?: 0)
        result = 31 * result + (appId?.hashCode() ?: 0)
        result = 31 * result + (clusterId?.hashCode() ?: 0)
        return result
    }
}


enum class MessageDeliveryMode {

    /**
     * 非持久
     */
    NON_PERSISTENT,

    /**
     * 持久
     */
    PERSISTENT;

    fun toInt(): Int {
        return when (this) {
            NON_PERSISTENT -> 1
            PERSISTENT -> 2
        }
    }

    companion object {

        fun fromInt(modeAsNumber: Int): MessageDeliveryMode? {
            return when (modeAsNumber) {
                1 -> NON_PERSISTENT
                2 -> PERSISTENT
                else -> null
            }
        }
    }
}